﻿Namespace Global.System.Collections

    Public Module Extension

        <Extension()> _
        Public Function ToString(ByRef [Me] As IList, Optional ByVal spliter As String = ",") As String
            Dim str As String = ""
            For Each item As Object In [Me]
                str += item.ToString() + spliter
            Next item
            str = "{" + str.Trim().Substring(0, str.Trim().Length - 1) + "}"
            Return str
        End Function

        <Extension()> _
        Public Function ToString(ByRef [Me] As IList, ByVal transformer As Func(Of Object, String), Optional ByVal spliter As String = ",", Optional ByVal prefix As String = "{", Optional ByVal postfix As String = "}") As String
            Dim str As String = ""
            For Each item As Object In [Me]
                str += transformer(item) + spliter
            Next
            str = prefix + str.Trim().Substring(0, str.LastIndexOf(spliter)) + postfix
            Return str
        End Function

        <Extension()> _
        Public Function ToArray(Of U, T)(ByVal [Me] As IList(Of U), ByVal trans As Func(Of U, T)) As T()
            Dim lst As New List(Of T)
            For Each item In [Me]
                lst.Add(trans(item))
            Next
            Return lst.ToArray()
        End Function

        <Extension()> _
        Public Iterator Function Convert(Of U, T)(ByVal [Me] As IEnumerable(Of U), ByVal trans As Func(Of U, T)) As IEnumerable(Of T)
            For Each item In [Me]
                Yield trans(item)
            Next
        End Function

        <Extension()> _
        Public Function RemoveIf(Of T)(ByVal [Me] As IList(Of T), ByVal predict As Func(Of T, Boolean)) As Boolean
            For Each item In [Me]
                If predict(item) Then
                    [Me].Remove(item)
                    Return True
                End If
            Next
            Return False
        End Function

        <Extension()> _
        Public Function Contains(Of T)(ByVal [Me] As IList(Of T), ByVal predict As Func(Of T, Boolean), Optional ByRef obj As Object = Nothing) As Boolean
            For Each item In [Me]
                If predict(item) Then
                    obj = item
                    Return True
                End If
            Next
            Return False
        End Function

        <Extension()> _
        Public Function Contains(Of T)(ByVal [Me] As IEnumerable(Of T), ByVal predict As Func(Of T, Boolean), Optional ByRef obj As Object = Nothing) As Boolean
            For Each item In [Me]
                If predict(item) Then
                    obj = item
                    Return True
                End If
            Next
            Return False
        End Function

        <Extension()> _
        Public Function Contains(Of T)(ByVal [Me] As IList(Of T), ByVal predict As Func(Of T, Boolean), ByRef refItem As T) As Boolean
            For Each item In [Me]
                If predict(item) Then
                    refItem = item
                    Return True
                End If
            Next
            Return False
        End Function

        <Extension()> _
        Public Function RemoveIf(Of T)(ByVal [Me] As ICollection(Of T), ByVal predict As Func(Of T, Boolean)) As Boolean
            Try
                For Each item In [Me]
                    If predict(item) Then
                        [Me].Remove(item)
                    End If
                Next
                Return True
            Catch ex As Exception
                Return False
            End Try
        End Function

        <Extension()> _
        Public Function RemoveFirstIf(Of T)(ByVal [Me] As ICollection(Of T), ByVal predict As Func(Of T, Boolean)) As Boolean
            For Each item In [Me]
                If predict(item) Then
                    [Me].Remove(item)
                    Return True
                End If
            Next
            Return False
        End Function

        <Extension()> _
        Public Function RemoveAll(Of T)(ByVal [Me] As ICollection(Of T), ByVal match As System.Predicate(Of T)) As Boolean
            Dim lst As New List(Of Integer)
            For i As Integer = 0 To [Me].Count - 1
                If match([Me](i)) Then
                    lst.Add(i)
                End If
            Next
            For Each item In lst
                [Me].Remove([Me](item))
            Next
            Return False
        End Function

        <Extension()> _
        Public Function Exists(Of T)(ByVal [Me] As ICollection(Of T), ByVal match As System.Predicate(Of T)) As Boolean
            Return [Me].Contains(Function(item) match(item))
        End Function

        ''' <summary>
        ''' Return the index of specified value in the dictionary.
        ''' </summary>
        ''' <typeparam name="TKey"></typeparam>
        ''' <typeparam name="TValue"></typeparam>
        ''' <param name="Me"></param>
        ''' <param name="value"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Extension()> _
        Public Function IndexOfValue(Of TKey, TValue)(ByVal [Me] As Dictionary(Of TKey, TValue), ByVal value As TValue) As Integer
            Dim i As Integer = 0
            With [Me].GetEnumerator()
                While .MoveNext()
                    If .Current.Value.Equals(value) Then
                        Return i
                    End If
                    i += 1
                End While
            End With
            Return -1
        End Function

        <Extension()> _
        Public Function At(Of TKey, TValue)(ByVal [Me] As Dictionary(Of TKey, TValue), ByVal index As Integer) As KeyValuePair(Of TKey, TValue)
            Dim i As Integer = 0
            If index >= 0 And index < [Me].Count Then
                With [Me].GetEnumerator()
                    While .MoveNext()
                        If i = index Then
                            Return .Current
                        End If
                        i += 1
                    End While
                End With
                Return Nothing
            Else
                Throw New IndexOutOfRangeException(String.Format("Index {0} for the dictionary is out of range.", index.ToString()))
            End If
        End Function

    End Module

End Namespace